package post

import (
	"context"
	"strconv"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/utils/pointy"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/blog/model"
	"mall/service/blog/rpc/internal/svc"
	"mall/service/blog/rpc/internal/utils/errorhandler"
	"mall/service/blog/rpc/types/blog"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetPostByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetPostByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetPostByIdLogic {
	return &BackendGetPostByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetPostByIdLogic) BackendGetPostById(in *blog.PostIdReq) (*blog.PostInfo, error) {
	if in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	res, err := l.svcCtx.Post.FindOne(l.ctx, in.Id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	var content *string
	var contentFiltered *string
	if in.WithContent != nil && *in.WithContent > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogPostDetailColumns.PostID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.Post.GetDetailList(l.ctx, model.M{
			"pageSize": uint64(1),
			"orderBy":  model.BlogPostDetailColumns.DetailID + " DESC",
			"select":   model.BlogPostDetailColumns.PostContent + "," + model.BlogPostDetailColumns.PostContentFiltered,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			content = pointy.GetPointer(list[0].PostContent)
			contentFiltered = pointy.GetPointer(list[0].PostContentFiltered)
		}
	}

	var meta []*blog.MetaInfo
	var futureStatus int64
	var pendingStatus int64
	var commentCount int64
	var sticky int32
	if in.WithMeta != nil && *in.WithMeta > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogPostMetumColumns.PostID] = map[string][]any{
			"equalTo": {in.Id},
		}
		list, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				if len(v.MetaKey) > 0 && (v.MetaKey == "_thumbnail_id" || v.MetaKey == "_thumbnail_url") {
					continue
				}

				if len(v.MetaKey) > 0 && v.MetaValue.Valid {
					key := v.MetaKey
					val := v.MetaValue.String
					switch key {
					case "_future_status":
						if i, err := strconv.ParseInt(val, 10, 32); err == nil {
							futureStatus = i
						}
					case "_pending_status":
						if i, err := strconv.ParseInt(val, 10, 32); err == nil {
							pendingStatus = i
							meta = append(meta, &blog.MetaInfo{
								Id:    &v.MetaID,
								Key:   pointy.GetPointer("pendingStatus"),
								Value: pointy.GetPointer(val),
							})
						}
					case "_photo_count":
						meta = append(meta, &blog.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("photoCount"),
							Value: pointy.GetPointer(val),
						})
					case "_view_count":
						meta = append(meta, &blog.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("viewCount"),
							Value: pointy.GetPointer(val),
						})
					case "_comment_count":
						if i, err := strconv.ParseInt(val, 10, 32); err == nil {
							commentCount = i
						}
					case "_forward_count":
						meta = append(meta, &blog.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer("forwardCount"),
							Value: pointy.GetPointer(val),
						})
					case "_sticky":
						switch val {
						case "frontpage":
							sticky = globalkey.BlogStickyTypeFrontpage
						case "category":
							sticky = globalkey.BlogStickyTypeCategory
						case "tag":
							sticky = globalkey.BlogStickyTypeTag
						}
					case "_upvote_count", "title_extra", "keywords_extra", "description_extra":
						//
					default:
						meta = append(meta, &blog.MetaInfo{
							Id:    &v.MetaID,
							Key:   pointy.GetPointer(key),
							Value: pointy.GetPointer(val),
						})
					}
				}
			}
		}
	}
	status := int32(res.PostStatus)
	if pendingStatus == 0 && futureStatus > 0 {
		status = int32(futureStatus)
	}
	finalStatus := int32(res.PostStatus)
	if futureStatus > 0 {
		finalStatus = int32(futureStatus)
	} else if pendingStatus > 0 {
		finalStatus = int32(pendingStatus)
	}
	var password *string
	visibility := globalkey.PostVisibilityPublic
	switch finalStatus {
	case globalkey.PostStatusPublish:
		if len(res.PostPassword) > 0 {
			password = pointy.GetPointer(res.PostPassword)
			visibility = globalkey.PostVisibilityPasswordProtected
		}
	case globalkey.PostStatusPrivate:
		visibility = globalkey.PostVisibilityPrivate
	}

	var media []*blog.TmpMediaInfo
	if in.WithMedia != nil && *in.WithMedia > 0 {
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		filterMap[model.BlogAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypePost},
		}
		var orderBy string = model.BlogAttachmentRelationshipColumns.AttachmentThumbnail + " DESC, " +
			model.BlogAttachmentRelationshipColumns.AttachmentOrder
		list, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
			"orderBy": orderBy,
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			for _, v := range list {
				media = append(media, &blog.TmpMediaInfo{
					Uid:       &v.AttachmentRelationshipID,
					Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
					Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
					Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
					Uri:       &v.AttachmentSource,
					Url:       &v.AttachmentImageURL,
					AltText:   &v.AttachmentImageAlt,
					MetaData:  &v.AttachmentImageMeta,
				})
			}
		}
	}

	var categories []*blog.TermInfo
	var tags []*blog.TermInfo
	if (in.WithCategory != nil && *in.WithCategory > 0) || (in.WithTag != nil && *in.WithTag > 0) {
		subFilterMap := make(map[string]map[string][]any)
		subFilterMap[model.BlogTermRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {in.Id},
		}
		subFilterMap[model.BlogTermRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.PostTypePost},
		}
		list, _, err := l.svcCtx.Term.GetRelationshipList(l.ctx, model.M{
			"select": model.BlogTermRelationshipColumns.ObjectID + "," + model.BlogTermRelationshipColumns.TermID,
		}, -1, subFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			var tids []any
			for _, v := range list {
				tids = append(tids, v.TermID)
			}

			termFilterMap := make(map[string]map[string][]any)
			termFilterMap[model.BlogTermColumns.TermID] = map[string][]any{
				"in": tids,
			}
			terms, _, err := l.svcCtx.Term.GetList(l.ctx, model.M{}, -1, termFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(terms) > 0 {
				for _, term := range terms {
					if term.Taxonomy == uint16(globalkey.TermTaxonomyCategory) { // 是分类
						if in.WithCategory != nil && *in.WithCategory > 0 {
							categories = append(categories, &blog.TermInfo{
								Id:   &term.TermID,
								Name: &term.Name,
								Slug: &term.Slug,
							})
						}
					} else if term.Taxonomy == uint16(globalkey.TermTaxonomyTag) { // 是标签
						if in.WithTag != nil && *in.WithTag > 0 {
							tags = append(tags, &blog.TermInfo{
								Id:   &term.TermID,
								Name: &term.Name,
								Slug: &term.Slug,
							})
						}
					}
				}
			}
		}
	}

	return &blog.PostInfo{
		Id:              &res.ID,
		Title:           &res.PostTitle,
		Slug:            &res.PostName,
		Content:         content,
		ContentFiltered: contentFiltered,
		Excerpt:         &res.PostExcerpt,
		Status:          pointy.GetPointer(uint32(status)),
		CommentStatus:   pointy.GetPointer(uint32(res.CommentStatus)),
		Sort:            pointy.GetPointer(uint32(res.MenuOrder)),
		Uri:             &res.GUID,
		AuthorId:        &res.PostAuthorID,
		ParentId:        &res.PostParentID,
		Visibility:      pointy.GetPointer(visibility),
		Password:        password,
		Sticky:          pointy.GetPointer(uint32(sticky)),
		CreatedAt:       pointy.GetPointer(modelx.FormatTime(res.PostDate, "")),
		UpdatedAt:       pointy.GetPointer(modelx.FormatTime(res.PostModifiedDate, "")),
		DeletedAt:       pointy.GetPointer(modelx.FormatNullDotTime(res.DeletedAt, "")),
		CommentCount:    pointy.GetPointer(uint32(commentCount)),
		Meta:            meta,
		Media:           media,
		Categories:      categories,
		Tags:            tags,
	}, nil
}
